package com.xbh.realtime.tio.websocket;

import com.jfinal.kit.StrKit;
import com.xbh.realtime.tio.messageQueue.TioNewLinkThread;
import com.xbh.realtime.tio.messageQueue.TioSubThread;
import com.xbh.realtime.tio.messageQueue.TioSubscriber;
import com.xbh.realtime.tio.srv.NotHelloAsyncSolver;
import org.tio.core.ChannelContext;
import org.tio.core.Tio;
import org.tio.core.intf.Packet;
import org.tio.http.common.HttpRequest;
import org.tio.http.common.HttpResponse;
import org.tio.websocket.common.WsPacket;
import org.tio.websocket.common.WsRequest;
import org.tio.websocket.common.WsResponse;
import org.tio.websocket.server.handler.IWsMsgHandler;

import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.function.Predicate;

/**
 * @MyWSMsgHandler:
 * @author: ZBoHang
 * @time: 2021/8/11 10:25
 */
public class MyWSMsgHandler implements IWsMsgHandler {

    // 唯一，保持连接的服务器(别名)编号
    private static long connectionNumber = 0;

    // 实时连接数量
    private static long activeClientCount = 0;

    // 当前连接中的 服务器编号 和 频道上下文
    private static Map<String, ChannelContext> channelContextMap = new ConcurrentHashMap<>();


    //  channelContext 的集合
    // private static

    // 线程池
    private static ExecutorService executors = Executors.newFixedThreadPool(5);

    public static final MyWSMsgHandler me = new MyWSMsgHandler();

    private static boolean flag = true;

    @Override
    public HttpResponse handshake(HttpRequest httpRequest, HttpResponse httpResponse, ChannelContext channelContext) throws Exception {
        System.out.println("去握手<<--");
        return httpResponse;
    }

    @Override
    public void onAfterHandshaked(HttpRequest httpRequest, HttpResponse httpResponse, ChannelContext channelContext) throws Exception {

        System.out.println("握手后<<--");
        // 此处可加判断 是否是正常连接 例如可以从请求路径入手
        String path = httpRequest.getRequestLine().getPath();
        String currentServerName = path.substring(path.indexOf("/") + 1);
        System.out.println("这是getRequestLine().getPath() -->> " + path);
        if (StrKit.notBlank(currentServerName)) {
            // 请求路径不空白 或者满足一定要求 正常访问
            long currentServerId = newConnection();
            String msg = channelContext.getClientNode().toString() + " 进来了，现在共有【" + getConnectionCount() + "】人在线";
            System.out.println("-->新的客户端加入"+msg);

            channelContextMap.put(currentServerName, channelContext);

            TioNewLinkThread tioNewLinkThread = new TioNewLinkThread(channelContext);
            tioNewLinkThread.start();

            //第一次连接时订阅 指定的频道
            if (flag) {
                toSubscriber();
            }
        } else {
            newConnection();
            WsResponse wsResponse = WsResponse.fromText("请输入正确的路径,路径中必须带有用户名 例如：ws://host:port/zhangsan", MyWSConfig.characterPattern);
            WsPacket wsPacket = wsResponse;
            Tio.bSend(channelContext, wsPacket);
            Tio.remove(channelContext, "路径错误");
        }
    }

    private synchronized void toSubscriber() {
        if (flag) {
            flag = false;
            TioSubscriber tioSubscriber = new TioSubscriber(channelContextMap);
            TioSubThread tioSubThread = new TioSubThread(tioSubscriber);
            tioSubThread.start();
        }
    }

    @Override
    public Object onBytes(WsRequest wsRequest, byte[] bytes, ChannelContext channelContext) throws Exception {
        System.out.println("接收到字节消息后<<--");
        return null;
    }

    @Override
    public Object onClose(WsRequest wsRequest, byte[] bytes, ChannelContext channelContext) throws Exception {
        System.out.println("handler关闭后<<--");
        return null;
    }

    @Override
    public Object onText(WsRequest wsRequest, String s, ChannelContext channelContext) throws Exception {
        System.out.println("接收到字符消息后<<--");
        if (StrKit.notBlank(s)) {
            if("quit".equals(s)) {
                WsResponse wsResponse = WsResponse.fromText("再见 走好 ~ ~ ~", MyWSConfig.characterPattern);
                Tio.send(channelContext, wsResponse);
                Tio.remove(channelContext, "主动退出");
            } else {
                String clientNode = channelContext.getClientNode().toString();
                executors.execute(new NotHelloAsyncSolver("【" + clientNode + "】 说：" + s));
            }
        }
        return null;
    }

    /**
     * id计数器
     */
    private static final synchronized long newConnection() {
        activeClientCount++;
        connectionNumber++;
        return connectionNumber;
    }

    private static synchronized long getConnectionNumber() {
        return connectionNumber;
    }

    public static final synchronized long getConnectionCount() {
        return activeClientCount;
    }

    public static final synchronized void destroyConnection() {
        activeClientCount--;
    }
}
